home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / mm-0.90 / mbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  10.1 KB  |  333 lines

  1. /*
  2.  * Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  * the City of New York.  Permission is granted to any individual or
  4.  * institution to use, copy, or redistribute this software so long as it
  5.  * is not sold for profit, provided this copyright notice is retained.
  6.  */
  7.  
  8. #ifndef lint
  9. static char *rcsid = "$Header: /f/src2/encore.bin/cucca/mm/tarring-it-up/RCS/mbox.c,v 2.2 90/10/04 18:24:42 melissa Exp $";
  10. #endif
  11.  
  12. /* mbox.c: routines to handle unix mbox format mail files */
  13.  
  14. #include "mm.h"                /* good stuff! */
  15. #include "rd.h"
  16.  
  17. #define key "From "            /* key to mbox format */
  18. #define keysize (sizeof(key)/sizeof(char))-1 /* don't count the null */
  19. #define flagkey "Flags: "        /* key for flags field */
  20. #define flagsize (sizeof(flagkey)/sizeof(char))-1
  21.  
  22. extern int local_close();
  23. char *fgetline();
  24. static char *cache;
  25.  
  26. /*
  27.  * mbox_open:
  28.  * see rd.h comments about open
  29.  */
  30. mbox_open (mail,flags)
  31. msgvec *mail;
  32. int flags;
  33. {
  34.     return (local_contig_open (mail,flags));
  35. }
  36.  
  37. /*
  38.  * see rd.h comments about close
  39.  */
  40. mbox_close (fp)
  41. FILE *fp;
  42. {
  43.     local_close (fp);
  44.     if (cache) {
  45.     free(cache);
  46.     cache = NULL;
  47.     }
  48. }
  49.                    
  50.  
  51. /*
  52.  * mbox_rdmsg:
  53.  * see rd.h comments about rd_msg
  54.  * Each mbox format message starts with a line of the form "From sender date"
  55.  * which may be followed by a flags line.
  56.  */
  57. mbox_rdmsg(mail,num) 
  58. msgvec *mail;
  59. int num;
  60. {
  61.     char *header;            /* initial line of a message */
  62.     char *cp, *from;
  63.     int line;                /* offset in text of line start */
  64.     u_long size, flags = 0, keybits = 0;
  65.     char *text;                /* body of message */
  66.     time_t date;
  67.     int buflen, space;            /* for snarfing in the body */
  68.     int eof, inheaders;            /* end of file yet?  in headers? */
  69.     message *m;
  70.  
  71.     if (num > mail->count)        /* can't read more than we have */
  72.        return (RD_FAIL);        /* not there */
  73.  
  74.     if (mail->last_read > num) {     /* gotta go back to it */
  75.     if (cache) {
  76.         free(cache);
  77.         cache = NULL;
  78.     }
  79.         rewind (mail->filep);        /* have to start from beginning */
  80.     mail->last_read = 0;        /* haven't read msg 1 */
  81.     }
  82.  
  83.     if (cache) {
  84.     header = cache;
  85.     cache = NULL;
  86.     }
  87.     else
  88.     header = fgetline(mail->filep);    /* do fgets till we get it all */
  89.     if (header == NULL)            /* if not even close, fail */
  90.         return ((mail->last_read < num-1) ? RD_FAIL : RD_EOF);
  91.     if (strncmp (header, key, keysize) != 0) {
  92.         fail_msg (mail->last_read + 1);    /* aww...  on our first message!  */
  93.     free (header);
  94.     return (RD_FAIL);        /* doesn't have any! */
  95.     }
  96.  
  97.     /* skip over the ones we don't want */
  98.     while (++mail->last_read < num) {    /* starting to read next message */
  99.         do {
  100.         free (header);
  101.         header = fgetline (mail->filep); /* try the next line */
  102.         if (header == NULL) {
  103.         if (mail->last_read < num - 1) {
  104.             fail_msg (mail->last_read+1);
  105.             return (RD_FAIL);
  106.         }
  107.         else
  108.             return (RD_EOF);
  109.         }
  110.     } while (strncmp (header, key, keysize) !=0); /* till new msg */
  111.     }                    /* do next message */
  112.  
  113.     /* now we have the header for the message we want */
  114.     cp = &header[keysize];        /* skip "From " (key) */
  115.     while (isspace (*cp) && *cp != '\0') /* get to actual name */
  116.     cp++;
  117.     from = cp;                /* here's the name */
  118.  
  119.     while (!isspace (*cp) && *cp != '\0') { /* break on whitespace */
  120.     if (*cp == '"')            /* ignore inter-quote stuff */
  121.         while (*(++cp) != '"' && *cp != '\0');
  122.     cp++;                /* skip non-space */
  123.     }
  124.     if (*cp != '\0')            /* anything left? */
  125.     *(cp++) = '\0';            /* end from field */
  126.  
  127.     while (isspace (*cp) && *cp != '\0') /* get to date */
  128.     cp++;
  129.  
  130.     /* about ready to parse the date, if there's any header left */
  131.     if (*cp == 0) {
  132.         fail_msg (mail->last_read--);    /* no good */
  133.     free (header);
  134.     return (RD_FAIL);
  135.     }
  136.  
  137. /*    date = stringtotime (cp); */
  138.     date = mbox_date(cp);
  139.     if (date == 0)
  140.         fprintf (stderr,"Message %d has bad date string (continuing)\n", num);
  141.  
  142.     /* now get the rest of the message */
  143.     buflen = 0;
  144.     text = cp = malloc (buflen += 100);    /* get some space for body of msg */
  145.     space = buflen;            /* all empty so far */
  146.     eof = false;            /* not the end yet */
  147.     inheaders = true;            /* start out reading the headers */
  148.     do {
  149.         line = cp - text;        /* starting a line */
  150.     if (space < 10) {
  151.         text = (char *) realloc (text, buflen += 100);
  152.         space += 100;        /* used the rest (but for '\0') */
  153.         cp = &text[buflen-space];    /* room to complete line */
  154.     }
  155.         if (fgets (cp, space, mail->filep) == NULL) { /* try to get a line */
  156.         eof = true;            /* end of file, that's it */
  157.         continue;            /* go down to the "while" */
  158.     }
  159.     while (index (cp, '\n') == NULL) { /* get the WHOLE line */
  160.         text = (char *) realloc (text, buflen +=100);
  161.         space = 101;        /* used the rest (but for '\0') */
  162.         cp = &text[buflen-space];    /* room to complete line */
  163.         if (fgets (cp, space, mail->filep) == NULL) {
  164.             eof = true;        /* end of file */
  165.         break;            /* out of inner while */
  166.         }
  167.     }
  168.  
  169.     if (eof)
  170.         continue;            /* get out of outer while */
  171.  
  172.     if (text[line] == '\n')        /* blank line */
  173.         inheaders = false;
  174.     if (inheaders &&
  175.         (ustrncmp (&text[line], flagkey, flagsize) == 0)) { /* flags */
  176.         if (sscanf(&text[line]+flagsize,"%6lo%6lo",&keybits,&flags) !=2) {
  177.         fail_msg (mail->last_read--);
  178.         return (RD_FAIL);
  179.         }
  180.         text[line] = '\0';        /* forget this line */
  181.         space = space + (cp - &text[line]);    /* reclaim that */
  182.         cp = &text[line];        /* back to beginning */
  183.     }
  184.     else {
  185.         while (*cp)            /* get to null */
  186.             cp++;            /* keep going */
  187.         space = buflen - (cp - text); /* what we haven't used */
  188.     }
  189.     } while (!eof && (strncmp (&text[line], key, keysize) != 0));
  190.  
  191.     if (!eof) {                /* unread the from */
  192.     cache = (char *)safe_strcpy(&text[line]);
  193.     text[line] = '\0';        /* stop before it */
  194.     text = (char *) realloc (text, (size = line) +1); /* snug to fit */
  195.     }
  196.     else
  197.         text = (char *) realloc (text, (size = (strlen (text))) +1);
  198.  
  199.     m = &mail->msgs[num];
  200.     m->date = date;
  201.     m->from = malloc (strlen (from) +1); /* need space */
  202.     strcpy (m->from, from);
  203.     m->size = size;
  204.     m->flags = flags;
  205.     m->keybits = keybits;
  206.     m->text = text;
  207.     m->keywords = nil;
  208.     get_incoming_keywords(mail,m);
  209.     free (header);            /* AFTER copying from field */
  210.     return (RD_OK);            /* got the message! */
  211. }
  212.  
  213.  
  214. /*
  215.  * mbox_wrmsg:
  216.  * see rd.h comments about wr_msg
  217.  * Each mbox format message starts with a line of the form "From sender date"
  218.  * and then has the special flags line, and then contains the text.
  219.  *
  220.  * We need a sender.  msg->from is best, but if we read in a
  221.  * non-mbox format we'll have to make something up.  Sender is
  222.  * preferable to From, but if we don't find anything, at least say
  223.  * something.   
  224.  */
  225. mbox_wrmsg(mail,msg,num,flags)
  226. msgvec *mail;
  227. message *msg;
  228. int num;
  229. int flags;
  230. {
  231.   int err;
  232.   char *from, *from2, *htext();
  233.   int freep;                /* do we have to free "from"? */
  234.   int i,j;
  235.   char *tbeg, *tfrom;            /* "beg" of text and "From" loc */
  236.   char *quote;
  237.  
  238.   if (!(flags & (WR_SAVE | WR_COPY))) {    /* not a save or copy */
  239.       mail->flags |= MF_DIRTY;        /* mark it to be saved */
  240.       return (false);            /* no error */
  241.   }
  242.   if ((msg->flags & M_DELETED) && (flags & WR_EXP)) {
  243.       if (num == mail->count)
  244.       local_get_size(mail);
  245.       return (false);            /* don't save deleted messages */
  246.   }
  247.  
  248.   /* if we have a from field already, we won't have to free it */
  249.   if (freep = (((from = msg->from) == NULL) || (from[0] == '\0')))
  250.       /* no internal from */
  251.       if ((from = htext ("sender", msg->text)) == NULL) /* "Sender:" field? */
  252.       if ((from = htext ("from", msg->text)) == NULL) { /* no, "From:"? */
  253.           from = "???";        /* who knows?? */
  254.           freep = false;        /* don't try to free that! */
  255.       }
  256.  
  257.   /* do we need to quote the address? read in msg->from, it was good then */
  258.   if (freep &&                /* taken from a header, check it */
  259.       (index(from,' ') || index(from,'\t'))) { /* needs quoting */
  260.       from2 = malloc (strlen(from)+3); /* adding two quotes */
  261.       from2[0] = '"';            /* going to have to quote it */
  262.       for (i = 0, j = 1; from[i] != '\0'; i++)
  263.       if (from[i] != '"') {        /* don't copy internal quotes */
  264.           from2[j] = from[i];
  265.           j++;
  266.       }
  267.       from2[j] = '"'; from2[j+1] = '\0';
  268.       free (from);            /* done with old copy */
  269.       from = from2;
  270.   }
  271.  
  272.   fprintf(mail->filep,"From %s %s",from, ctime(&msg->date));
  273.   fprintf(mail->filep,"%s%06lo%06lo\n",flagkey,
  274.       msg->keybits, (msg->flags & M_INTERNAL));
  275.   if (freep)
  276.       free (from);            /* we malloced it */
  277.   /* now check for "\nFrom " and write out text */
  278.   tbeg = msg->text;            /* point to start of text */
  279.   while ((tfrom = search ("\nFrom ", tbeg)) != NULL) {
  280.       /* write up to and including \n first */
  281.       if (fwrite (tbeg, tfrom - tbeg + 1, 1, mail->filep) != 1)
  282.       return (errno);
  283.       fprintf (mail->filep, ">From ");    /* quote the From */
  284.       tbeg = tfrom+6;            /* rest of string */
  285.   }
  286.   fwrite (tbeg, sizeof(char), strlen(tbeg), mail->filep);
  287.   if (msg->text[msg->size-1] != '\n')    /* trailing newline required */
  288.       fputc ('\n', mail->filep);
  289.  
  290.   if ((fflush (mail->filep) == EOF) ||    /* make sure we get it out */
  291.       (ferror(mail->filep) != 0))
  292.       return (true);
  293.   if (flags & WR_SAVE) {        /* we saved it */
  294.       msg->flags &= ~M_MODIFIED;    /* it's not modified anymore  */
  295.       if (num == mail->count)
  296.       local_get_size(mail);
  297.   }
  298.   return (false);            /* no error */
  299. }
  300.  
  301.  
  302. /*
  303.  * probe file to see if it's in mbox format
  304.  * mbox format is distinctive in that the file starts with "From "
  305.  */
  306. mbox_probe(file)
  307. char *file;
  308. {
  309.     FILE *fp;
  310.     char p[keysize +1];        /* enough to probe it, with null */
  311.     int i;
  312.     int ret;
  313.  
  314.     if (cf && same_file(cf->filename, file)) {
  315.     if (cf->type == TYPE_MBOX) 
  316.         return (PR_OK);
  317.     else
  318.         return (PR_NOTOK);
  319.     }
  320.     if ((ret = local_contig_proben (file, &fp)) != PR_OK)
  321.     return (ret);            /* couldn't open it */
  322.     i = fread (p, sizeof (char), keysize, fp);
  323.     fclose (fp);            /* okay, we're done looking */
  324.     if (i == 0)
  325.     return (PR_EMPTY);        /* empty file */
  326.     if (i < keysize) 
  327.         return (PR_NOTOK);        /* not ok, not enough characters */
  328.     p[i] = '\0';            /* finish the string */
  329.     if (strcmp (p, key) != 0)
  330.     return (PR_NOTOK);        /* doesn't look right */
  331.     return (PR_OK);            /* passed! */
  332. }
  333.